package sys

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/vueadmin/app/admin/internal/svc"
	"github.com/vueadmin/utils"
	"github.com/vueadmin/utils/common/result"
	"github.com/vueadmin/utils/conv"
	"github.com/vueadmin/utils/response"
	"gorm.io/gorm"
	"net/http"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const url = "http://gobuild.whpj.cc"

const pkgname = "github.com/vueadmin"

var System = new(sys)

var conns = []map[string]interface{}{
	{"name": "db", "type": "mysql", "prefix": "cd_"}, //默认连接配置信息
}

type sys struct{}

// 根据别名获取数据连接
func (p sys) Conn(svcCtx *svc.ServiceContext, connectName string) *gorm.DB {
	if connectName == "" {
		connectName = "db"
	}
	switch connectName {
	case "db":
		return svcCtx.Db
	}
	return svcCtx.Db
}

// 获取mysql前缀
func (p sys) GetPrefix(connectName string) string {
	connect := ""
	for _, v := range conns {
		if connectName == conv.String(v["name"]) {
			connect = conv.String(v["prefix"])
		}
	}
	return connect
}

// 根据连接名获取数据库类型
func (p sys) GetDBTypeByConnect(connectName string) string {
	connect := "mysql"
	for _, v := range conns {
		if connectName == conv.String(v["name"]) {
			connect = conv.String(v["type"])
		}
	}
	return connect
}

// 读取秘钥
func (p sys) GetSecrectInfo(c *gin.Context, svcCtx *svc.ServiceContext) {
	var secrectInfo []SecrectColumns
	svcCtx.Db.Find(&secrectInfo)

	config := make(map[string]interface{})

	for _, val := range secrectInfo {
		config[val.Name] = val.Data
	}
	response.Success(c, "ok", config)
}

// 更新秘钥
func (p sys) Secrect(c *gin.Context, svcCtx *svc.ServiceContext) {
	var secrectInfo SecrectData
	if err := utils.BindAndValid(c, &secrectInfo); err != nil {
		response.Fail(c, err.Error())
		return
	}

	data := make([]string, 0)
	svcCtx.Db.Model(&SecrectColumns{}).Pluck("name", &data)

	var typeInfo = reflect.TypeOf(secrectInfo)
	var typeValue = reflect.ValueOf(secrectInfo)
	for num := 0; num < typeInfo.NumField(); num++ {
		name := typeInfo.Field(num).Tag.Get("json")
		if conv.IsValueInList(name, data) {
			svcCtx.Db.Model(&SecrectColumns{}).Where("name = ?", name).Update("data", typeValue.Field(num).String())
		} else {
			svcCtx.Db.Model(&SecrectColumns{}).Create(&SecrectColumns{Name: name, Data: typeValue.Field(num).String()})
		}
	}

	response.Success(c, "更新成功", true)
}

// 应用列表
func (p sys) ApplicationList(c *gin.Context, svcCtx *svc.ServiceContext) {
	var application []Application
	if err := svcCtx.Db.Order("app_id asc").Find(&application).Error; err != nil {
		panic(err)
	}
	data := make(map[string]interface{})
	data["data"] = application

	response.Success(c, "ok", data)
}

type AppReq struct {
	AppId int `form:"app_id" json:"app_id" validate:"required"` //应用Id
}

// 应用详情
func (p sys) GetApplicationInfo(c *gin.Context, svcCtx *svc.ServiceContext) {
	var req AppReq
	var data Application
	if err := utils.BindAndValid(c, &req); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if req.AppId == 0 {
		response.Fail(c, "参数错误")
		return
	}
	if err := svcCtx.Db.Where("app_id=?", req.AppId).Find(&data).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", data)
}

// 创建应用
func (p sys) CreateApplication(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data Application
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if data.AppType == 4 {
		count := 0
		for _, item := range data.Expand {
			if item == "beanstalkd" || item == "kafka" || item == "rabbitmq" {
				count++
				if count > 1 {
					response.Fail(c, "只允许设置一种类型消费队列")
					return
				}
			}
		}
	}
	if data.AppType == 2 {
		if conv.Int(data.Limit) > 0 && !conv.IsValueInList("redis", data.Expand) {
			response.Fail(c, "设置限流必须使用redis!")
			return
		}
	}
	if err := svcCtx.Db.Create(&data).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", nil)
}

// 修改应用
func (p sys) UpdateApplication(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data Application
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if data.AppType == 4 {
		count := 0
		for _, item := range data.Expand {
			if item == "beanstalkd" || item == "kafka" || item == "rabbitmq" {
				count++
				if count > 1 {
					response.Fail(c, "只允许设置一种类型消费队列")
					return
				}
			}
		}
	}
	if data.AppType == 2 {
		if conv.Int(data.Limit) > 0 && !conv.IsValueInList("redis", data.Expand) {
			response.Fail(c, "设置限流必须使用redis!")
			return
		}
	}
	if err := svcCtx.Db.Select("*").Updates(&data).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", data.AppId)
}

// 删除应用
func (p sys) DeleteApplication(c *gin.Context, svcCtx *svc.ServiceContext) {
	data := c.Value("data").(AppReq)
	if err := svcCtx.Db.Where("app_id", data.AppId).Delete(&Application{}).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", data.AppId)
}

// 获取配置信息列表
func (p sys) GetUploadList(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data []map[string]interface{}
	svcCtx.Db.Table("cd_upload_config").Select("id,title").Find(&data)
	response.Success(c, "ok", data)
}

// 根据数据库名获取数据库类型
func (p sys) GetDbType(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	name := p.GetDBTypeByConnect(conv.String(data["dbname"]))
	response.Success(c, "ok", name)
}

func (p sys) GetTreeRecursive(list []*Menu, parentId int) []*Menu {
	res := make([]*Menu, 0)
	for _, v := range list {
		if int(v.Pid) == parentId {
			v.Children = p.GetTreeRecursive(list, int(v.MenuId))
			res = append(res, v)
		}
	}
	return res
}

type menuListReq struct {
	AppId string `form:"app_id" json:"app_id" validate:"required"` //应用Id
}

// 获取菜单列表
func (p sys) MenuList(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data []*Menu
	var application []map[string]interface{}
	var param menuListReq

	if err := utils.BindAndValid(c, &param); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if err := svcCtx.Db.Where("app_id", param.AppId).Order("sortid asc").Find(&data).Error; err != nil {
		panic(err)
	}

	svcCtx.Db.Model(&Application{}).Where("app_type in ?", []int{1, 2}).Find(&application)

	for _, v := range application {
		v["url"] = "/admin/Menu/index?app_id=" + strconv.Itoa(int(v["app_id"].(uint))) + "&app_type=" + conv.String(v["app_type"])
	}

	res := p.GetTreeRecursive(data, 0)

	connect := make([]string, 0)

	for _, v := range conns {
		connect = append(connect, conv.String(v["name"]))
	}

	c.JSON(http.StatusOK, result.M{
		"status":         200,
		"list":           res,
		"connects":       connect,
		"defaultConnect": "mysql",
		"tableList":      p.getTableList(svcCtx, "db"),
		"page_type_list": GetPageTypeList(),
		"app_list":       application,
	})
}

type MenuReq struct {
	MenuId int `form:"menu_id" json:"menu_id"`
}

// 获取菜单详情
func (p sys) GetMenuInfo(c *gin.Context, svcCtx *svc.ServiceContext) {
	var req MenuReq
	var data Menu
	if err := utils.BindAndValid(c, &req); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if err := svcCtx.Db.Where("menu_id", req.MenuId).Find(&data).Error; err != nil {
		return
	}
	response.Success(c, "ok", data)
}

// 更新菜单
func (p sys) UpdateMenu(c *gin.Context, svcCtx *svc.ServiceContext) {
	data := c.Value("data").(Menu)

	data.ControllerName = conv.ToCamelCase(conv.String(data.ControllerName))
	if err := svcCtx.Db.Model(&Menu{}).Select("*").Where("menu_id", data.MenuId).Updates(&data).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", true)
}

// 创建菜单
func (p sys) CreateMenu(c *gin.Context, svcCtx *svc.ServiceContext) {
	data := c.Value("data").(Menu)
	data.ControllerName = conv.ToCamelCase(data.ControllerName)
	if err := svcCtx.Db.Create(&data).Error; err != nil {
		panic(err)
	}
	svcCtx.Db.Model(&Menu{}).Where("menu_id", data.MenuId).Update("sortid", data.MenuId)
	if data.Tablename != "" && data.Pk != "" && data.CreateCode > 0 && data.Status > 0 {
		if data.PageType == 1 {
			//创建默认操作方法以及字段
			for _, val := range GetActionList() {
				if val["default_create"] != nil && val["default_create"].(bool) && !conv.IsValueInList(strconv.Itoa(val["type"].(int)), []string{"10", "11"}) {
					noCreateField := []string{"button", "default_create", "dialog", "show_admin", "show_api", "view"}
					for _, v := range noCreateField {
						delete(val, v)
					}
					val["menu_id"] = data.MenuId
					if err := svcCtx.Db.Model(&Action{}).Create(val).Error; err != nil {
						panic(err)
					}
				}
			}

			var (
				datatype string
				width    string
				pk       string
			)
			if p.GetDBTypeByConnect(data.Connect) == "mongodb" {
				datatype = "varchar"
				width = "220"
				pk = "_id"
			} else {
				datatype = "int"
				width = "70"
				pk = data.Pk
			}
			//创建默认字段
			field := &Field{
				Title:            "编号",
				Type:             1,
				Datatype:         datatype,
				Length:           "11",
				ListShow:         2,
				CreateTableField: 1,
				Sortid:           1,
				Width:            width,
				MenuId:           conv.String(data.MenuId),
				Field:            pk,
				ItemConfig:       []map[string]interface{}{},
				OtherConfig:      map[string]interface{}{},
			}
			if err := svcCtx.Db.Create(&field).Error; err != nil {
				panic(err)
			}
		}

		//创建单页面方法
		if data.PageType == 2 {
			action := &Action{
				Name:               data.Title,
				MenuId:             conv.String(data.MenuId),
				ActionName:         "index",
				Type:               14,
				ServerCreateStatus: 1,
				VueCreateStatus:    1,
			}
			if err := svcCtx.Db.Create(&action).Error; err != nil {
				panic(err)
			}
		}
	}

	response.Success(c, "操作成功", data.MenuId)
}

type CopyMenuReq struct {
	MenuId int `form:"menu_id" json:"menu_id"`
	Appid  int `form:"appid" json:"appid"`
}

// 复制菜单
func (p sys) CopyMenu(c *gin.Context, svcCtx *svc.ServiceContext) {
	var (
		data        CopyMenuReq
		menu        Menu
		application Application
		fieldList   []Field
		actionList  []Action
	)
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if err := svcCtx.Db.Where("menu_id", data.MenuId).First(&menu).Error; err != nil {
		panic(err)
	}

	if err := svcCtx.Db.Where("app_id", data.Appid).First(&application).Error; err != nil {
		panic(err)
	}
	menu.MenuId = 0
	menu.AppId = conv.String(data.Appid)
	menu.Pid = 0
	menu.CreateTable = 0

	if err := svcCtx.Db.Create(&menu).Error; err != nil {
		panic(err)
	}

	if err := svcCtx.Db.Where("menu_id", data.MenuId).Find(&fieldList).Error; err != nil {
		panic(err)
	}

	if err := svcCtx.Db.Where("menu_id", data.MenuId).Find(&actionList).Error; err != nil {
		panic(err)
	}

	for _, v := range fieldList {
		v.Id = 0
		v.MenuId = conv.String(menu.MenuId)
		v.CreateTableField = 0
		v.OtherConfig = map[string]interface{}{}
		if conv.IsValueInList(conv.String(v.ListShow), []string{"0", "1"}) && application.AppType == 2 {
			v.ListShow = 0
		}
		if conv.IsValueInList(conv.String(v.ListShow), []string{"2", "3", "4"}) && application.AppType == 2 {
			v.ListShow = 1
		}
		if conv.IsValueInList(conv.String(v.Type), []string{"2", "3", "4", "5", "35"}) && application.AppType == 2 {
			if !conv.IsEmpty(v.Sql) {
				v.Type = 1
			}
		}
		v.Sql = ""
		if err := svcCtx.Db.Create(&v).Error; err != nil {
			panic(err)
		}
	}

	for _, v := range actionList {
		if conv.IsValueInList(conv.String(v.Type), []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "20"}) {
			v.Id = 0
			v.MenuId = conv.String(menu.MenuId)
			v.ListFilter = []map[string]interface{}{}
			v.TabConfig = []map[string]interface{}{}
			v.WithJoin = []map[string]interface{}{}
			if err := svcCtx.Db.Create(&v).Error; err != nil {
				panic(err)
			}
		}
	}

	response.Success(c, "操作成功", nil)
}

// 删除菜单
func (p sys) DeleteMenu(c *gin.Context, svcCtx *svc.ServiceContext) {
	data := c.Value("data").(MenuReq)
	if err := svcCtx.Db.Where("menu_id", data.MenuId).Delete(&Menu{}).Error; err != nil {
		panic(err)
	}

	svcCtx.Db.Where("menu_id", data.MenuId).Delete(&Action{})
	svcCtx.Db.Where("menu_id", data.MenuId).Delete(&Field{})

	response.Success(c, "操作成功", true)
}

// 修改菜单2
func (p sys) UpdateMenuExt(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if err := svcCtx.Db.Model(&Menu{}).Where("menu_id", data["menu_id"]).Updates(data).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", true)
}

// 字段列表
func (p sys) FieldList(c *gin.Context, svcCtx *svc.ServiceContext) {
	var request Base
	if err := utils.BindAndValid(c, &request); err != nil {
		response.Fail(c, err.Error())
		return
	}
	var field []Field
	if err := svcCtx.Db.Order("sortid asc").Where("menu_id = ?", request.MenuId).Limit(request.Limit).Offset((request.Page - 1) * request.Limit).Find(&field).Error; err != nil {
		panic(err)
	}
	var total int64
	svcCtx.Db.Model(&Field{}).Where("menu_id = ?", request.MenuId).Count(&total)

	var menu Menu
	svcCtx.Db.Select("title").Where("menu_id = ?", request.MenuId).Take(&menu)

	var application []Application
	svcCtx.Db.Find(&application)

	c.JSON(http.StatusOK, result.M{
		"status":     200,
		"data":       map[string]interface{}{"data": field, "total": total},
		"typeField":  GetFieldList(),
		"itemList":   GetItemList(),
		"menu_title": menu.Title,
		"app_list":   application,
	})
}

type IdReq struct {
	Id int `form:"id" json:"id" validate:"required"` //应用Id
}

func (p sys) GetFieldInfo(c *gin.Context, svcCtx *svc.ServiceContext) {
	var req IdReq
	var data Field
	if err := utils.BindAndValid(c, &req); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if err := svcCtx.Db.Where("id = ?", req.Id).Find(&data).Error; err != nil {
		panic(err)
	}
	if data.OtherConfig == nil {
		data.OtherConfig = map[string]interface{}{}
	}

	if _, ok := data.OtherConfig["shuxing"]; !ok {
		data.OtherConfig["shuxing"] = []string{}
	}

	if len(data.ItemConfig) == 0 {
		data.ItemConfig = []map[string]interface{}{}
	}

	response.Success(c, "ok", data)
}

// 创建字段
func (p sys) CreateField(c *gin.Context, svcCtx *svc.ServiceContext) {
	data := c.Value("data").(Field)
	for _, val := range GetFieldList() {
		if data.Type == conv.Int8(val["type"]) && val["search"] == true {
			data.SearchType = 1
		}
	}
	data.PostStatus = true
	if !conv.IsEmpty(data.BelongTable) {
		data.PostStatus = false
		data.SearchType = 0
	}
	if err := svcCtx.Db.Create(&data).Error; err != nil {
		panic(err)
	}
	if data.Id > 0 {
		svcCtx.Db.Model(&Field{}).Where("id", data.Id).Update("sortid", data.Id)
	}
	response.Success(c, "ok", data.Id)
}

// 修改字段
func (p sys) UpdateField(c *gin.Context, svcCtx *svc.ServiceContext) {
	data := c.Value("data").(Field)
	if !conv.IsEmpty(data.BelongTable) {
		data.PostStatus = false
	}
	if err := svcCtx.Db.Select("*").Updates(&data).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", true)
}

// 修改字段2
func (p sys) UpdateFieldExt(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if err := svcCtx.Db.Model(&Field{}).Where("id", data["id"]).Updates(data).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", true)
}

// 删除字段
func (p sys) DeleteField(c *gin.Context, svcCtx *svc.ServiceContext) {
	data := c.Value("data").(map[string]interface{})
	if data["id"] == "" {
		response.Fail(c, "id不能为空")
		return
	}
	if err := svcCtx.Db.Where("id", data["id"]).Delete(&Field{}).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", true)
}

// 同步字段
func (p sys) CopyField(c *gin.Context, svcCtx *svc.ServiceContext) {
	var (
		data        map[string]interface{}
		menu        Menu
		targetmenu  Menu
		field       Field
		targetField Field
	)
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}

	if err := svcCtx.Db.Where("menu_id", data["menu_id"]).First(&menu).Error; err != nil {
		panic(err)
	}

	if err := svcCtx.Db.Where("app_id", data["appid"]).Where("table_name", menu.Tablename).Find(&targetmenu).Error; err != nil {
		panic(err)
	}
	if targetmenu.MenuId == 0 {
		response.Fail(c, "目标菜单不存在")
		return
	}
	for _, v := range data["field_id"].([]interface{}) {
		if err := svcCtx.Db.Where("id", v).Find(&field).Error; err != nil {
			panic(err)
		}

		if err := svcCtx.Db.Where("field", field.Field).Where("menu_id", targetmenu.MenuId).Find(&targetField).Error; err != nil {
			panic(err)
		}
		if targetField.Field == "" {
			field.CreateTableField = 0
			field.MenuId = conv.String(targetmenu.MenuId)
			field.Id = 0
			if conv.IsValueInList(conv.String(field.ListShow), []string{"2", "3", "4"}) {
				field.ListShow = 1
			}
			if err := svcCtx.Db.Create(&field).Error; err != nil {
				panic(err)
			}
		}
	}

	response.Success(c, "ok", true)
}

// 方法列表
func (p sys) ActionList(c *gin.Context, svcCtx *svc.ServiceContext) {
	var request = Base{}
	if err := utils.BindAndValid(c, &request); err != nil {
		response.Fail(c, err.Error())
		return
	}

	var action []Action
	if err := svcCtx.Db.Order("sortid asc").Where("menu_id = ?", request.MenuId).Limit(request.Limit).Offset((request.Page - 1) * request.Limit).Find(&action).Error; err != nil {
		panic(err)
	}

	var total int64
	svcCtx.Db.Model(&Action{}).Where("menu_id = ?", request.MenuId).Count(&total)

	var menu Menu
	svcCtx.Db.Select("title").Where("menu_id = ?", request.MenuId).Take(&menu)

	c.JSON(http.StatusOK, result.M{
		"status":     200,
		"data":       map[string]interface{}{"data": action, "total": total},
		"menu_title": menu.Title,
		"actionList": GetActionList(),
	})
}

// 获取方法详情
func (p sys) GetActionInfo(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data Action
	var req IdReq
	if err := utils.BindAndValid(c, &req); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if err := svcCtx.Db.Model(&Action{}).Where("id", req.Id).Find(&data).Error; err != nil {
		panic(err)
	}
	if len(data.OtherConfig) == 0 {
		data.OtherConfig = map[string]interface{}{
			"hook": []string{},
		}
	} else {
		if _, ok := data.OtherConfig["hook"]; !ok {
			data.OtherConfig = map[string]interface{}{
				"hook": []string{},
			}
		}
	}
	if len(data.ListFilter) == 0 {
		data.ListFilter = []map[string]interface{}{}
	}
	if len(data.WithJoin) == 0 {
		data.WithJoin = []map[string]interface{}{}
	}
	if len(data.TabConfig) == 0 {
		data.TabConfig = []map[string]interface{}{}
	}
	if len(data.SearchField) == 0 {
		data.SearchField = []string{}
	}
	response.Success(c, "ok", data)
}

// 创建方法
func (p sys) CreateAction(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data Action
	c.ShouldBindBodyWith(&data, binding.JSON)
	var total int64
	svcCtx.Db.Model(&Action{}).Where("menu_id = ?", data.MenuId).Where("action_name = ?", data.ActionName).Count(&total)
	if total > 0 {
		response.Fail(c, "方法已经存在")
		return
	}
	if conv.IsValueInList(strconv.Itoa(int(data.Type)), []string{"2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "15", "16", "17", "18", "19", "20", "21"}) {
		data.GroupButtonStatus = 1
	}

	if conv.IsValueInList(strconv.Itoa(int(data.Type)), []string{"2", "3", "19", "21"}) {
		data.DialogSize = "600px"
	}

	if data.Type == 51 {
		data.CacheTime = 600
	}

	if conv.IsValueInList(strconv.Itoa(int(data.Type)), []string{"3", "4"}) {
		data.ListButtonStatus = 1
	}

	delete_type := conv.String(data.OtherConfig["delete_type"])
	if delete_type == "soft_delete" {
		var menu Menu
		svcCtx.Db.Select("connect", "table_name").Where("menu_id = ?", data.MenuId).First(&menu)
		if !conv.IsValueInList("deleted_at", p.GetFields(svcCtx, menu.Connect, p.GetPrefix(menu.Connect)+menu.Tablename)) && p.GetDBTypeByConnect(menu.Connect) == "mysql" {
			var sql = fmt.Sprintf("ALTER TABLE %s ADD %s %s%s COMMENT '%s' %s", p.GetPrefix(menu.Connect)+menu.Tablename, "deleted_at", "datetime", " null", "软删除标记", "DEFAULT NULL")
			fmt.Println(sql, menu.Connect)
			if err := svcCtx.Db.Exec(sql).Error; err != nil {
				panic(err)
			}
		}
	}

	var with_join []map[string]interface{}
	if len(data.WithJoin) > 0 {
		for _, val := range data.WithJoin {
			var menuinfo map[string]interface{}
			svcCtx.Db.Model(&Menu{}).Where("controller_name", val["relative_table"]).Take(&menuinfo)
			val["connect"] = "mysql"
			val["table_name"] = menuinfo["table_name"]
			with_join = append(with_join, val)
		}
	}

	if err := svcCtx.Db.Create(&data).Error; err != nil {
		panic(err)
	}
	if data.Id > 0 {
		svcCtx.Db.Model(&Action{}).Where("id", data.Id).Update("sortid", data.Id)
	}
	response.Success(c, "ok", data.Id)
}

// 更新方法
func (p sys) UpdateAction(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data Action
	c.ShouldBindBodyWith(&data, binding.JSON)
	delete_type := conv.String(data.OtherConfig["delete_type"])
	if delete_type == "soft_delete" {
		var menu Menu
		svcCtx.Db.Select("connect,table_name").Where("menu_id = ?", data.MenuId).First(&menu)
		if !conv.IsValueInList("deleted_at", p.GetFields(svcCtx, menu.Connect, p.GetPrefix(menu.Connect)+menu.Tablename)) && p.GetDBTypeByConnect(menu.Connect) == "mysql" {
			var sql = fmt.Sprintf("ALTER TABLE %s ADD %s %s%s COMMENT '%s' %s", p.GetPrefix(menu.Connect)+menu.Tablename, "deleted_at", "datetime", " null", "软删除标记", "DEFAULT NULL")
			if err := svcCtx.Db.Exec(sql).Error; err != nil {
				panic(err)
			}
		}
	}

	var with_join []map[string]interface{}
	if len(data.WithJoin) > 0 {
		for _, val := range data.WithJoin {
			var menuinfo map[string]interface{}
			svcCtx.Db.Model(&Menu{}).Where("controller_name", val["relative_table"]).Take(&menuinfo)
			val["connect"] = "mysql"
			val["table_name"] = menuinfo["table_name"]
			with_join = append(with_join, val)
		}
	}

	data.WithJoin = with_join

	if err := svcCtx.Db.Select("*").Updates(&data).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", data.Id)
}

// 修改方法2
func (p sys) UpdateActionExt(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if err := svcCtx.Db.Model(&Action{}).Where("id", data["id"]).Updates(data).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", true)
}

// 根据菜单id获取所有数据表
func (p sys) GetTablesByMenuId(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	var app_id int64
	svcCtx.Db.Model(&Menu{}).Where("menu_id", data["menu_id"]).Pluck("app_id", &app_id)

	var table_list []map[string]interface{}
	svcCtx.Db.Model(&Menu{}).Select("table_name,title").Where("app_id", app_id).Where("table_name <> ?", " ").Find(&table_list)

	response.Success(c, "ok", table_list)
}

// 方法列表拖动排序
func (p sys) UpdateActionSort(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if data["preSortId"] != nil && data["nextSortId"] != nil && data["currentSortId"].(float64) > data["preSortId"].(float64) && data["currentSortId"].(float64) < data["nextSortId"].(float64) {
		response.Fail(c, "操作失败")
		return
	}

	if data["preSortId"] == nil && data["nextSortId"] != nil && data["currentSortId"].(float64) < data["nextSortId"].(float64) {
		response.Fail(c, "操作失败")
		return
	}

	if data["preSortId"] != nil && data["nextSortId"] == nil && data["currentSortId"].(float64) > data["preSortId"].(float64) {
		response.Fail(c, "操作失败")
		return
	}

	var pre int64
	if data["preId"].(float64) > 0 {
		svcCtx.Db.Model(&Action{}).Where("id", data["preId"]).Where("menu_id", data["menu_id"]).Pluck("sortid", &pre)
	}

	var next int64
	if data["nextId"].(float64) > 0 {
		svcCtx.Db.Model(&Action{}).Where("id", data["nextId"]).Where("menu_id", data["menu_id"]).Pluck("sortid", &next)
	}

	var current int64
	svcCtx.Db.Model(&Action{}).Where("id", data["currentId"]).Where("menu_id", data["menu_id"]).Pluck("sortid", &current)

	var sortid int64
	if current > pre {
		sortid = next
	} else {
		sortid = pre
	}

	if pre == 0 {
		pre = next - 1
		sortid = next
	}

	if next == 0 {
		next = pre + 1
		sortid = pre
	}

	if current > pre {
		svcCtx.Db.Model(&Action{}).Where("sortid between ? and ?", pre+1, current-1).Where("menu_id", data["menu_id"]).UpdateColumn("sortid", gorm.Expr("sortid + ?", 1))
	}
	if current < pre {
		svcCtx.Db.Model(&Action{}).Where("sortid between ? and ?", current+1, next-1).Where("menu_id", data["menu_id"]).UpdateColumn("sortid", gorm.Expr("sortid - ?", 1))
	}
	svcCtx.Db.Model(&Action{}).Where("id", data["currentId"]).Where("menu_id", data["menu_id"]).Update("sortid", sortid)

	response.Success(c, "ok", true)
}

// 字段列表拖动排序
func (p sys) UpdateFieldSort(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}

	if data["preSortId"] != nil && data["nextSortId"] != nil && data["currentSortId"].(float64) > data["preSortId"].(float64) && data["currentSortId"].(float64) < data["nextSortId"].(float64) {
		response.Fail(c, "操作失败")
		return
	}

	if data["preSortId"] == nil && data["nextSortId"] != nil && data["currentSortId"].(float64) < data["nextSortId"].(float64) {
		response.Fail(c, "操作失败")
		return
	}

	if data["preSortId"] != nil && data["nextSortId"] == nil && data["currentSortId"].(float64) > data["preSortId"].(float64) {
		response.Fail(c, "操作失败")
		return
	}

	var pre int64
	if data["preId"].(float64) > 0 {
		svcCtx.Db.Model(&Field{}).Where("id", data["preId"]).Where("menu_id", data["menu_id"]).Pluck("sortid", &pre)
	}

	var next int64
	if data["nextId"].(float64) > 0 {
		svcCtx.Db.Model(&Field{}).Where("id", data["nextId"]).Where("menu_id", data["menu_id"]).Pluck("sortid", &next)
	}

	var current int64
	svcCtx.Db.Model(&Field{}).Where("id", data["currentId"]).Where("menu_id", data["menu_id"]).Pluck("sortid", &current)

	var sortid int64
	if current > pre {
		sortid = next
	} else {
		sortid = pre
	}

	if pre == 0 {
		pre = next - 1
		sortid = next
	}

	if next == 0 {
		next = pre + 1
		sortid = pre
	}

	if current > pre {
		svcCtx.Db.Model(&Field{}).Where("sortid between ? and ?", pre+1, current-1).Where("menu_id", data["menu_id"]).UpdateColumn("sortid", gorm.Expr("sortid + ?", 1))
	}
	if current < pre {
		svcCtx.Db.Model(&Field{}).Where("sortid between ? and ?", current+1, next-1).Where("menu_id", data["menu_id"]).UpdateColumn("sortid", gorm.Expr("sortid - ?", 1))
	}
	svcCtx.Db.Model(&Field{}).Where("id", data["currentId"]).Where("menu_id", data["menu_id"]).Update("sortid", sortid)

	response.Success(c, "ok", true)
}

// 删除方法
func (p sys) DeleteAction(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if data["id"] == "" {
		response.Fail(c, "id不能为空")
		return
	}
	if err := svcCtx.Db.Where("id", data["id"]).Delete(&Action{}).Error; err != nil {
		panic(err)
	}
	response.Success(c, "ok", true)
}

// 获取字段相关的配置信息
func (p sys) ConfigList(c *gin.Context, svcCtx *svc.ServiceContext) {
	c.JSON(http.StatusOK, result.M{
		"status":        200,
		"ruleList":      GetRuleList(),
		"propertyField": GetPropertyField(),
		"dbtype":        "mysql",
	})
}

type MenuIdReq struct {
	MenuId string `form:"menu_id" json:"menu_id"`
}

// 获取操作的字段
func (p sys) GetPostField(c *gin.Context, svcCtx *svc.ServiceContext) {
	var field []map[string]interface{}
	var tableList []map[string]interface{}
	var menu map[string]interface{}
	var list []map[string]interface{}
	var action []Action
	var tab_field []map[string]interface{}
	var search_field []map[string]interface{}

	var request = MenuIdReq{}
	if err := utils.BindAndValid(c, &request); err != nil {
		response.Fail(c, err.Error())
		return
	}

	svcCtx.Db.Table("cd_field").Select("type,field,title,post_status").Where("menu_id = ?", request.MenuId).Find(&field)
	svcCtx.Db.Table("cd_menu").Select("connect,table_name,app_id").Where("menu_id", request.MenuId).Take(&menu)

	for _, val := range field {
		if val["post_status"] != nil && val["post_status"].(int64) == 1 {
			list = append(list, val)
		}
		search_field = append(search_field, val)
	}

	with_join := make([]interface{}, 0)

	svcCtx.Db.Table("cd_action").Where("menu_id", request.MenuId).Find(&action)
	for _, val := range action {
		if len(val.WithJoin) > 0 && conv.IsValueInList(strconv.Itoa(int(val.Type)), []string{"2", "3"}) {
			str, _ := json.Marshal(val.WithJoin)
			withjoin := conv.ToSliceMap(string(str))
			for _, j := range withjoin {
				with_join_field := p.getExtendFields(svcCtx, j)
				with_join = append(with_join, with_join_field)
			}
		}
	}

	tab_field = list

	for _, val := range with_join {
		for _, v := range val.([]map[string]interface{}) {
			tab_field = append(tab_field, v)
		}
	}

	svcCtx.Db.Table("cd_menu").Select("controller_name").Where("controller_name <> ?", " ").Where("app_id", menu["app_id"]).Find(&tableList)
	c.JSON(http.StatusOK, result.M{
		"status":       200,
		"sms_list":     GetSmsList(),
		"data":         list,
		"jump_field":   field,
		"model_fields": field,
		"tableList":    tableList,
		"dbtype":       "mysql",
		"tab_fields":   tab_field,
		"search_field": search_field,
	})
}

// 返回关联表的字段
func (p sys) getExtendFields(svcCtx *svc.ServiceContext, data map[string]interface{}) []map[string]interface{} {
	var menu Menu
	var field []map[string]interface{}
	var list []map[string]interface{}

	svcCtx.Db.Where("controller_name = ?", data["relative_table"]).Find(&menu)
	svcCtx.Db.Model(&Field{}).Select("type,field,title,post_status,datatype,item_config").Where("menu_id = ?", menu.MenuId).Find(&field)

	out := []string{}
	for _, v := range data["fields"].([]interface{}) {
		out = append(out, v.(string))
	}

	for _, val := range field {
		if conv.IsValueInList(val["field"].(string), out) {
			val["belong_table"] = data["relative_table"]
			val["table_name"] = menu.Tablename
			list = append(list, val)
		}
	}

	return list
}

// 获取app数据表信息
func (p sys) GetAppInfo(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	table_name := p.getTableName(data["controller_name"].(string))
	c.JSON(http.StatusOK, result.M{
		"status":     200,
		"table_name": table_name,
		"pk":         table_name + "_id",
		"app_name":   "admin",
	})
}

func (p sys) getTableName(controllerName string) string {
	if strings.Contains(controllerName, "/") {
		controllerName = strings.Split(controllerName, "/")[1]
	}
	return controllerName
}

// 获取表的字段
func (p sys) GetTableFields(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	var menu Menu
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if data["controller_name"] == nil {
		response.Fail(c, "控制器名称不能为空")
		return
	}
	svcCtx.Db.Where("controller_name", data["controller_name"]).Take(&menu)
	fields, _ := p.GetFullColumns(svcCtx, menu.Connect, p.GetPrefix(menu.Connect)+menu.Tablename)

	c.JSON(http.StatusOK, result.M{
		"status":    200,
		"filedList": fields,
	})
}

// 查询所有数据表
func (p sys) GetTables(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]string
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	show_table := p.getTableList(svcCtx, data["connect"])
	response.Success(c, "ok", show_table)
}

func (p sys) getTableList(svcCtx *svc.ServiceContext, connect string) []string {
	tables := make([]string, 0)
	p.Conn(svcCtx, connect).Raw("show tables").Pluck("Tables_in_mysql", &tables)

	no_table := []string{"menu", "application", "admin_user", "action", "log", "field"}
	show_table := make([]string, 0)

	for _, val := range tables {
		val = strings.Replace(val, p.GetPrefix(connect), "", -1)
		if !conv.IsValueInList(val, no_table) {
			show_table = append(show_table, val)
		}
	}
	return show_table
}

// 根据数据表获取主键
func (p sys) GetPkByTable(svcCtx *svc.ServiceContext, connect string, tablename string) string {
	data, _ := p.GetFullColumns(svcCtx, connect, tablename)
	var pk string
	for _, val := range data {
		if val.Key == "PRI" {
			pk = val.Field
		}
	}
	return pk
}

// 查询数据表的所有字段
func (p sys) GetFullColumns(svcCtx *svc.ServiceContext, connect string, tableName string) (fields []Columns, err error) {
	var data []Columns
	if err := p.Conn(svcCtx, connect).Raw("show full columns from " + tableName).Scan(&data).Error; err != nil {
		return nil, err
	} else {
		return data, nil
	}
}

// 生成应用
func (p sys) CreateApp(c *gin.Context, svcCtx *svc.ServiceContext) {
	var req AppReq
	if err := utils.BindAndValid(c, &req); err != nil {
		response.Fail(c, err.Error())
		return
	}
	var application Application
	if err := svcCtx.Db.Where("app_id = ?", req.AppId).First(&application).Error; err != nil {
		panic(err)
	}
	var secrectInfo []SecrectColumns
	svcCtx.Db.Find(&secrectInfo)

	secret := make(map[string]interface{})
	for _, val := range secrectInfo {
		secret[val.Name] = val.Data
	}
	if conv.IsEmpty(secret["appid"]) || conv.IsEmpty(secret["secrect"]) {
		response.Fail(c, "appid或者秘钥不能为空")
		return
	}
	param := make(map[string]interface{})
	param["secrect"] = secret
	param["timestmp"] = time.Now().Unix()
	param["application"] = application
	param["framwork"] = "gin"
	param["pkgname"] = pkgname
	param["sign"] = utils.Md5(utils.Md5(conv.String(param) + secret["secrect"].(string)))

	bytes, _ := utils.NewHttpRequest().Request("POST", url+"/index/Index/createApp", strings.NewReader(conv.String(param))).ParseBytes()

	var data map[string]interface{}
	json.Unmarshal(bytes, &data)
	if value, ok := data["status"]; ok && conv.Int(value) == 411 {
		response.Fail(c, conv.String(data["msg"]))
		return
	}

	currentDir, _ := os.Getwd()
	parentDir := filepath.Dir(currentDir)

	/*if ok, _ := utils.PathExists(parentDir + "/" + application.AppDir); ok {
		response.Fail(c, "应用已生成!")
		return
	}*/
	if len(data) > 0 {
		for _, v := range data {
			utils.FilePutContents(parentDir+"/"+v.(map[string]interface{})["path"].(string), v.(map[string]interface{})["content"].(string))
		}
	} else {
		fmt.Println(string(bytes))
	}
	c.JSON(http.StatusOK, result.M{
		"status": 200,
		"msg":    "生成成功",
	})
}

func (p sys) Create(c *gin.Context, svcCtx *svc.ServiceContext) {
	var data map[string]interface{}
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}
	if _, ok := data["menu_id"]; !ok {
		response.Fail(c, "menu_id不能为空")
		return
	}
	if err := p.CreateCode(svcCtx, conv.Int(data["menu_id"])); err != nil {
		response.Fail(c, err.Error())
		return
	}
	c.JSON(http.StatusOK, result.M{
		"status": 200,
		"msg":    "生成成功",
	})
}

func (p sys) CreateCode(svcCtx *svc.ServiceContext, menu_id int) error {
	var menu Menu
	if err := svcCtx.Db.Where("menu_id = ?", menu_id).First(&menu).Error; err != nil {
		panic(err)
	}
	var application Application
	if err := svcCtx.Db.Where("app_id = ?", menu.AppId).First(&application).Error; err != nil {
		panic(err)
	}
	currentDir, _ := os.Getwd()
	parentDir := filepath.Dir(currentDir)
	uiDir := filepath.Dir(parentDir)
	if ok, _ := utils.PathExists(parentDir + "/" + application.AppDir); !ok {
		return errors.New("请先生成应用!")
	}
	var field []map[string]interface{}
	if err := svcCtx.Db.Order("sortid asc").Model(&Field{}).Where("menu_id = ?", menu_id).Find(&field).Error; err != nil {
		panic(err)
	}
	var action []map[string]interface{}
	if err := svcCtx.Db.Order("sortid asc").Model(&Action{}).Where("menu_id = ?", menu_id).Find(&action).Error; err != nil {
		return err
	}

	dbtype := p.GetDBTypeByConnect(menu.Connect)
	tablename := p.GetPrefix(menu.Connect) + menu.Tablename

	tablelist := []string{"log", "admin_user"}
	for _, v := range p.getTableList(svcCtx, menu.Connect) {
		tablelist = append(tablelist, v)
	}

	if !conv.IsValueInList(menu.Tablename, tablelist) && dbtype == "mysql" {
		return errors.New("数据表不存在")
	}
	var pk string
	if dbtype == "mongodb" {
		pk = "_id"
	} else {
		pk = p.GetPkByTable(svcCtx, menu.Connect, tablename)
	}

	var secrectInfo []SecrectColumns
	svcCtx.Db.Find(&secrectInfo)

	secret := make(map[string]interface{})

	for _, val := range secrectInfo {
		secret[val.Name] = val.Data
	}
	if conv.IsEmpty(secret["appid"]) || conv.IsEmpty(secret["secrect"]) {
		return errors.New("appid或者秘钥不能为空")
	}
	param := make(map[string]interface{})
	param["fieldList"] = field
	param["actionList"] = action
	param["application"] = application
	param["pk"] = pk
	param["menuInfo"] = menu
	param["actions"] = GetActionList()
	param["secrect"] = secret
	param["timestmp"] = time.Now().Unix()
	param["framwork"] = "gin"
	param["ui"] = "vue2cli"
	param["router"] = getRouterContent(application.AppDir)
	param["extend"] = p.getExtend(svcCtx, action)
	param["pkgname"] = pkgname
	param["cachetype"] = "redis"
	param["dbtype"] = dbtype
	if dbtype != "mongodb" {
		param["dbpre"] = p.GetPrefix(menu.Connect)
	}
	param["sign"] = utils.Md5(utils.Md5(conv.String(param) + secret["secrect"].(string)))

	bytes, _ := utils.NewHttpRequest().Request("POST", url+"/index", strings.NewReader(conv.String(param))).ParseBytes()

	var data map[string]interface{}
	json.Unmarshal(bytes, &data)
	if value, ok := data["status"]; ok && conv.Int(value) == 411 {
		return errors.New(conv.String(data["msg"]))
	}

	if len(data) > 0 {
		for k, v := range data {
			if k == "jscomponent" {
				switch v.(type) {
				case map[string]interface{}:
					for _, val := range v.(map[string]interface{}) {
						utils.FilePutContents(uiDir+"/"+"ui/src/views/"+val.(map[string]interface{})["path"].(string), val.(map[string]interface{})["content"].(string))
					}
				case []interface{}:
					for _, val := range v.([]interface{}) {
						utils.FilePutContents(uiDir+"/"+"ui/src/views/"+val.(map[string]interface{})["path"].(string), val.(map[string]interface{})["content"].(string))
					}
				}
			} else {
				if k == "approuter" {
					utils.FilePutContents(parentDir+"/"+v.(map[string]interface{})["path"].(string), v.(map[string]interface{})["content"].(string))
				} else {
					BuildFunc(v.(map[string]interface{})["content"].(string), parentDir+"/"+v.(map[string]interface{})["path"].(string))
				}
			}
		}
		return nil
	} else {
		fmt.Println(string(bytes))
		return nil
	}
	return nil
}

// 根据表生成
func (p sys) CreateByTable(c *gin.Context, svcCtx *svc.ServiceContext) {
	var (
		data   map[string]interface{}
		menu   Menu
		action Action
		field  Field
	)
	if err := utils.BindAndValid(c, &data); err != nil {
		response.Fail(c, err.Error())
		return
	}

	connect := conv.String(data["connect"])

	tablename := p.GetPrefix(connect) + conv.String(data["table_name"])
	pk := p.GetPkByTable(svcCtx, connect, tablename)
	if conv.IsEmpty(pk) {
		response.Fail(c, "主键不存在，无法生成")
		return
	}

	fieldlist, err := p.GetFullColumns(svcCtx, connect, tablename)
	if err != nil {
		panic(err)
	}

	menu.ControllerName = conv.ToCamelCase(conv.String(data["table_name"]))
	menu.ComponentPath = fmt.Sprintf("admin/%s/index.vue", strings.Replace(strings.ToLower(conv.String(data["table_name"])), "_", "", -1))
	menu.Title = conv.String(data["table_name"])
	menu.Pk = pk
	menu.CreateCode = 1
	menu.CreateTable = 0
	menu.AppId = conv.String(data["app_id"])
	menu.Connect = connect
	menu.PageType = 1
	menu.Tablename = conv.String(data["table_name"])
	menu.Status = 1

	svcCtx.Db.Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(&menu).Error; err != nil {
			panic(err)
		}
		if err := tx.Model(&Menu{}).Where("menu_id", menu.MenuId).Update("sortid", menu.MenuId).Error; err != nil {
			panic(err)
		}

		actionList := GetActionList()
		for k, v := range actionList {
			if _, ok := v["default_create"]; ok {
				if !conv.IsValueInList(conv.String(v["type"]), []string{"10", "11", "17", "18", "19"}) {
					action.MenuId = conv.String(menu.MenuId)
					action.ActionName = conv.String(v["action_name"])
					action.Type = conv.Int8(v["type"])
					action.Name = conv.String(v["name"])
					action.Icon = conv.String(v["icon"])
					action.Sortid = conv.Int64(k) + 1
					action.ButtonColor = conv.String(v["button_color"])
					action.DialogSize = conv.String(v["dialog_size"])
					action.GroupButtonStatus = conv.Int8(v["group_button_status"])
					action.ListButtonStatus = conv.Int8(v["list_button_status"])
					action.ServerCreateStatus = 1
					action.VueCreateStatus = 1
					action.Id = 0
					action.SelectType = 1
					action.Pagesize = "20"
					action.TabConfig = []map[string]interface{}{}
					action.WithJoin = []map[string]interface{}{}
					action.ListFilter = []map[string]interface{}{}
					action.OtherConfig = map[string]interface{}{}
					if conv.String(data["app_type"]) == "2" && conv.Int8(v["type"]) == 12 {

					} else {
						if err := tx.Create(&action).Error; err != nil {
							panic(err)
						}
					}
				}
			}
		}

		for k, v := range fieldlist {
			if v.Field != "deleted_at" {
				field.MenuId = conv.String(menu.MenuId)
				if v.Comment != "" {
					field.Title = v.Comment
				} else {
					field.Title = v.Field
				}
				field.Field = v.Field
				field.Type = 1
				field.ListShow = 2
				field.SearchType = 0
				field.PostStatus = true
				field.CreateTableField = 0
				field.Sortid = conv.Int32(k) + 1
				if v.Field == pk {
					field.Width = "70"
					field.PostStatus = false
				} else {
					field.Width = ""
				}
				re := strings.Split(v.Type, "(")
				field.Datatype = re[0]

				pattern := `\((\d+)\)`

				ret := regexp.MustCompile(pattern)
				match := ret.FindStringSubmatch(v.Type)

				if len(match) > 1 {
					field.Length = match[1]
				} else {
					field.Length = "0"
				}

				field.Id = 0
				field.ItemConfig = []map[string]interface{}{}
				field.OtherConfig = map[string]interface{}{}

				if err := tx.Create(&field).Error; err != nil {
					panic(err)
				}
			}
		}
		return nil
	})
	if err := p.CreateCode(svcCtx, conv.Int(menu.MenuId)); err != nil {
		response.Fail(c, err.Error())
		return
	}
	c.JSON(http.StatusOK, result.M{
		"status": 200,
		"msg":    "生成成功",
	})
}

func (p sys) GetFields(svcCtx *svc.ServiceContext, connect string, tablename string) []string {
	var data []string
	fields, _ := p.GetFullColumns(svcCtx, connect, tablename)
	for _, val := range fields {
		data = append(data, val.Field)
	}
	return data
}

func getRouterContent(app string) string {
	currentDir, _ := os.Getwd()
	parentDir := filepath.Dir(currentDir)
	rootDir := filepath.Dir(parentDir)
	filename := rootDir + "/app/" + app + "/internal/route/routes.go"
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		return ""
	}
	content := utils.FileGetContents(filename)
	return content
}

func (p sys) getExtend(svcCtx *svc.ServiceContext, actions []map[string]interface{}) []map[string]interface{} {
	withjoin := make([]map[string]interface{}, 0)
	for _, v := range actions {
		if !conv.IsEmpty(v["with_join"]) && conv.IsValueInList(conv.String(v["type"]), []string{"2", "3"}) {
			for _, val := range conv.ToSliceMap(conv.String(v["with_join"])) {
				withjoin = append(withjoin, map[string]interface{}{
					"action_type":    v["type"],
					"fk":             val["fk"],
					"relative_table": val["relative_table"],
					"pk":             val["pk"],
					"table_name":     val["table_name"],
					"connect":        val["connect"],
					"fields":         p.getExtendFields(svcCtx, val),
				})
			}

		}
	}
	return withjoin
}
